package com.lin.missyou.logic;

import com.lin.missyou.bo.SkuOrderBO;
import com.lin.missyou.dto.OrderDTO;
import com.lin.missyou.dto.SkuInfoDTO;
import com.lin.missyou.exception.http.ParameterException;
import com.lin.missyou.model.OrderSku;
import com.lin.missyou.model.Sku;
import lombok.Getter;
import org.springframework.data.domain.jaxb.SpringDataJaxb;

import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * 订单效验
 *
 * 职责
 * 外观模式
 * OrderService->OrderChecker->CouponChecker
 * 重视设计模式
 *
 * 负责订单的效验
 * 通过public方法返回给到调用方
 * @author gcq
 * @Create 2021-11-09
 */
public class OrderChecker {

    /**
     * 前端传递过来的DTO
     */
    private OrderDTO orderDTO;
    /**
     * 根据传递的 skuid 查询出来的sku集合信息
     */
    private List<Sku> serverSkuList;
    /**
     * 优惠券效验器
     */
    private CouponChecker couponChecker;
    /**
     * 最大购买数量
     */
    private Integer maxSkuLimit;
    /**
     * orderSku
     */
    @Getter
    private List<OrderSku> orderSkuList = new ArrayList<>();

    public OrderChecker(OrderDTO orderDTO, List<Sku> serverSkuList,
                        CouponChecker couponChecker, Integer maxSkuLimit)
    {
        this.orderDTO = orderDTO;
        this.serverSkuList = serverSkuList;
        this.couponChecker = couponChecker;
        this.maxSkuLimit = maxSkuLimit;
    }

    public String getLeaderImg()
    {
        return this.serverSkuList.get(0).getImg();
    }
    public String getLeaderTitle()
    {
        return this.serverSkuList.get(0).getTitle();
    }

    /**
     * 获取当前购买数量
     *
     * map 拿到值
     * reduce 计算和
     * orelse 没有的话给0
     * @return
     */
    public Integer getTotalCount()
    {
        return this.orderDTO.getSkuInfoList()
                .stream()
                .map(SkuInfoDTO::getCount)
                .reduce(Integer::sum)
                .orElse(0);
    }

    /**
     * 效验
     * orderTotalPrice serverTotalPrice
     * 某些 Sku 下架
     * 售空的商品
     * 超出库存
     * 最大购买数量
     * 优惠券效验
     * 根据业务复杂度 checker
     */
    public void isOk()
    {
        // 服务器总价格
        BigDecimal serverTotalPrice = new BigDecimal("0");

        List<SkuOrderBO> skuOrderBOList = new ArrayList<>();

        // 计算前端传递过来的数量与服务端计算出来数量是否一致
        this.skuNotOnSale(orderDTO.getSkuInfoList().size(), this.serverSkuList.size());

        for(int i = 0; i < this.serverSkuList.size(); i++) {
            Sku sku = this.serverSkuList.get(i);

            SkuInfoDTO skuInfoDTO = this.orderDTO.getSkuInfoList().get(i);

            // 库存是否正确
            this.containsSoldOutSku(sku);

            // 库存是否对应
            this.beyondSkuStock(sku, skuInfoDTO);

            // 最大数量
            this.beyondMaxSkuLimit(skuInfoDTO);

            serverTotalPrice = serverTotalPrice.add(this.calculateSkuOrderPrice(sku, skuInfoDTO));
            skuOrderBOList.add(new SkuOrderBO(sku, skuInfoDTO));
        }
        // 总金额是否正确
        this.totalPriceIsOK(orderDTO.getTotalPrice(), serverTotalPrice);

        // 优惠券效验
        if(this.couponChecker != null)
        {
            // 优惠券是否过期
            this.couponChecker.isOk();
            // 是否可以使用
            this.couponChecker.canBeUsed(skuOrderBOList, serverTotalPrice);
            this.couponChecker.finalTotalPriceIsOK(orderDTO.getFinalTotalPrice(), serverTotalPrice);
        }
    }

    /**
     * 计算前端传递过来价格 与 服务端计算出是否一致
     * @param orderTotalPrice 前端传递过来的价格
     * @param serverTotalPrice 服务端计算出来的原价
     * @throws
     */
    private void totalPriceIsOK(BigDecimal orderTotalPrice, BigDecimal serverTotalPrice)
    {
        if(orderTotalPrice.compareTo(serverTotalPrice) != 0)
        {
            throw new ParameterException(50005);
        }
    }
    /**
     * 计算sku订单金额
     * @param sku 服务端查询出的sku
     * @param skuInfoDTO 前端传递DTO
     * @return sku 订单金额
     */
    private BigDecimal calculateSkuOrderPrice(Sku sku, SkuInfoDTO skuInfoDTO)
    {
        // 必须要有数量才能计算
        if(skuInfoDTO.getCount() <= 0)
        {
            throw new ParameterException(50007);
        }
        // 价格 * 数量
        // sku价格 * 前端传递过来的数量
        return sku.getActualPrice().multiply(new BigDecimal(skuInfoDTO.getCount()));
    }
    /**
     * 购买库存是否超过
     * @param sku 服务端查询出的sku
     * @param skuInfoDTO 前端传递过来的dto
     */
    private void beyondSkuStock(Sku sku, SkuInfoDTO skuInfoDTO) {
        // 服务端的库存量 小于 前端传递过来的数量 则抛出异常
        // 100 < 200
        if(sku.getStock() < skuInfoDTO.getCount())
        {
            throw new ParameterException(50003);
        }
    }

    /**
     * sku 是否售空
     * @param sku
     */
    private void containsSoldOutSku(Sku sku) {
        if(sku.getStock() == 0)
        {
            throw new ParameterException(50003);
        }
    }

    /**
     * 是否超过系统最大购买数量
     * @param skuInfoDTO
     * @exception ParameterException
     */
    private void beyondMaxSkuLimit(SkuInfoDTO skuInfoDTO)
    {
        if(skuInfoDTO.getCount() > this.maxSkuLimit)
        {
            throw new ParameterException(50004);
        }
    }

    /**
     * 服务前与前端数量计算是否一致
     * @param count1
     * @param count2
     */
    public void skuNotOnSale(int count1, int count2)
    {
        if(count1 != count2)
        {
            throw new ParameterException(50002);
        }
    }
}